﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using GameEngine;
using System.Diagnostics;
using System.Windows.Media.Animation;
using System.Globalization;
using Daphne.Presenters;
using System.Windows.Threading;

namespace Board2D
{
    /// <summary>
    /// Control for hosting the professional gameboard
    /// </summary>
    public class ProfessionalGameBoard : Control
    {

        #region Private Drawing Attributes

        private BitmapSource _imageBoardClassic = null;
        private BitmapSource _imageBoardBlackWhite = null;
        private BitmapSource _imageBoardMarble = null;
        private Rect _rectBoard;
        private BitmapSource _imageBoardRotClassic = null;
        private BitmapSource _imageBoardRotBlackWhite = null;
        private BitmapSource _imageBoardRotMarble = null;
        private Rect _rectBoardRotated;
        private BitmapSource _imageWhiteMan = null;
        private Rect _rectWhiteMan;
        private BitmapSource _imageBlackMan = null;
        private Rect _rectBlackMan;
        private BitmapSource _imageWhiteKing = null;
        private Rect _rectWhiteKing;
        private BitmapSource _imageBlackKing = null;
        private Rect _rectBlackKing;
        private BitmapSource _imageBoard10 = null;
        private Rect _rectBoard10;

        private DispatcherTimer _timer;
        private TTimerAction _timerAction;
        private eBoard2DTheme _theme;
      
        #endregion

        private IProfessionalGameBoardView _ProfessionalPresenter;
        private DrawingContext _DrawingContext;
        private const int _imageSize = 1024;
        private RenderTargetBitmap bitmap;

        private double _offsetX;
        private double _offsetY;

        private static Action EmptyDelegate = delegate() { };

        static ProfessionalGameBoard()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ProfessionalGameBoard), new FrameworkPropertyMetadata(typeof(ProfessionalGameBoard)));
        }

        public ProfessionalGameBoard()
        {
            PreloadImages();
            bitmap = new RenderTargetBitmap(_imageSize, _imageSize, 96, 96, PixelFormats.Default);


            _DrawingContext = null;
        }

        public void SetPresenter(IProfessionalGameBoardView presenter)
        {
            _ProfessionalPresenter = presenter;
            _ProfessionalPresenter.StartDrawEvent += new TStartDraw(_ProfessionalPresenter_StartDrawEvent);
            _ProfessionalPresenter.EndDrawEvent += new TEndDraw(_ProfessionalPresenter_EndDrawEvent);
            _ProfessionalPresenter.DrawTextEvent += new TDrawText(_ProfessionalPresenter_DrawTextEvent);
            _ProfessionalPresenter.DrawImageEvent += new TDrawImage(_ProfessionalPresenter_DrawImageEvent);
            _ProfessionalPresenter.DrawFilledRectangleEvent += new TDrawFilledRectangle(_ProfessionalPresenter_DrawFilledRectangleEvent);
            _ProfessionalPresenter.SetCaptureEvent += new TSetCapture(_ProfessionalPresenter_SetCaptureEvent);
            _ProfessionalPresenter.ReleaseCaptureEvent += new TReleaseCapture(_ProfessionalPresenter_ReleaseCaptureEvent);
            _ProfessionalPresenter.ControlRedrawEvent += new TControlRedraw(_ProfessionalPresenter_ControlRedrawEvent);
            _ProfessionalPresenter.StartTimerEvent += new TStartTimer(_ProfessionalPresenter_StartTimerEvent);
            _ProfessionalPresenter.StopTimerEvent += new TStopTimer(_ProfessionalPresenter_StopTimerEvent);

        }

        public void SetTheme(eBoard2DTheme theme)
        {
            _theme = theme;
        }

        void _ProfessionalPresenter_StopTimerEvent()
        {
            _timer.Stop();
        }

        void _ProfessionalPresenter_StartTimerEvent(uint miliseconds, TTimerAction action)
        {
            _timerAction = action;
            if (_timer != null)
            {
                if (_timer.IsEnabled)
                {
                    throw new ApplicationException("Cannot initiatialize timer while it is running.");
                }
            }
            else
            {
                _timer = new DispatcherTimer(DispatcherPriority.Normal);
                _timer.Tick += new EventHandler(_timer_Tick);
            }
            _timer.Interval = TimeSpan.FromMilliseconds(miliseconds);
            _timer.Start();
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            _timerAction();
        }

        public void Refresh()
        {
            InvalidateVisual();
            Application.Current.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
        }

        void _ProfessionalPresenter_ControlRedrawEvent()
        {
            InvalidateVisual();
        }

        void _ProfessionalPresenter_ReleaseCaptureEvent()
        {
            ReleaseMouseCapture();
        }

        void _ProfessionalPresenter_SetCaptureEvent()
        {
            CaptureMouse();
        }

        void _ProfessionalPresenter_DrawFilledRectangleEvent(TGameBoardDrawRect rect, string sColor, int alpha, int lBoundCurve)
        {
            Color clr = ConvertColor(sColor, alpha);
            Brush brush = new SolidColorBrush(clr);
            Pen pen = new Pen(brush, 1);
            _DrawingContext.DrawRoundedRectangle(brush, pen, ConvertRect(rect), (double)lBoundCurve, (double)lBoundCurve);
        }

        void _ProfessionalPresenter_DrawImageEvent(TGameBoardDrawRect rect, enumDrawnImage drawnImage, int alpha)
        {
            _DrawingContext.PushOpacity(ConvertAlpha(alpha));
            Rect rectWPF;
            BitmapSource image = GetImage(drawnImage, out rectWPF);
            _DrawingContext.DrawImage(image, ConvertRect(rect));
        }

        void _ProfessionalPresenter_DrawTextEvent(double  x, double y, string sText, string sColor)
        {
            FormattedText text = new FormattedText(sText, CultureInfo.CurrentUICulture,
                     System.Windows.FlowDirection.LeftToRight, new Typeface("Arial"), 18, Brushes.Yellow);
            _DrawingContext.DrawText(text, new Point(x, y));
        }

        void _ProfessionalPresenter_EndDrawEvent()
        {
        }

        void _ProfessionalPresenter_StartDrawEvent()
        {



        }


        protected override void OnMouseMove(MouseEventArgs e)
        {
            Point point = e.GetPosition(this);
            point = ConvertMousePosition(point);
            _ProfessionalPresenter.MouseMove((int)point.X, (int)point.Y);
            this.InvalidateVisual();
        }


        protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(this);
            point = ConvertMousePosition(point);
            _ProfessionalPresenter.RightButtonUp((int)point.X, (int)point.Y);
            this.InvalidateVisual();
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(this);
            point = ConvertMousePosition(point);
            _ProfessionalPresenter.LeftButtonDown((int)point.X, (int)point.Y);
            this.InvalidateVisual();
        }

        protected override void  OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            Point point = e.GetPosition(this);
            point = ConvertMousePosition(point);
            _ProfessionalPresenter.LeftButtonUp((int)point.X, (int)point.Y);
            this.InvalidateVisual();
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            // draw in design
            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(
                new DependencyObject()) == true)
            {
                SolidColorBrush designBrush = new SolidColorBrush(Colors.Aqua);
                Pen designPen = new Pen(designBrush, 1);
                drawingContext.DrawRectangle(designBrush, designPen,
                            new Rect(0, 0, RenderSize.Width, RenderSize.Height));
                return;
            }

            // set drawing context
            _DrawingContext = drawingContext;

            // calculate translation transform
            double size = Math.Min(RenderSize.Width, RenderSize.Height);
            _offsetX = (RenderSize.Width - size) / 2;
            _offsetY = (RenderSize.Height - size) / 2;
            drawingContext.PushTransform(new TranslateTransform(_offsetX, _offsetY));

            // calculate scale transform
            double scale = size / _imageSize;
            drawingContext.PushTransform(new ScaleTransform(scale, scale));

            // render board
            _ProfessionalPresenter.DrawBoard();

            // clear transform
            drawingContext.Pop();
            drawingContext.Pop();

            // tidy up
            base.OnRender(drawingContext);
            _DrawingContext = null;
        }

        private double ConvertAlpha(int alpha)
        {
            return (double)alpha / 255;
        }

        private Rect ConvertRect(TGameBoardDrawRect rect)
        {
            return new Rect((double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height);
        }

        private Color ConvertColor(string sColor, int alpha)
        {
            string sRed = sColor.Substring(0, 2);
            string sGreen = sColor.Substring(2, 2);
            string sBlue = sColor.Substring(4, 2);

            Color clr = Color.FromArgb((byte)alpha
                    , (byte)ConvertFromHex(sRed)
                    , (byte)ConvertFromHex(sGreen)
                    , (byte)ConvertFromHex(sBlue));
            return clr;
        }

        private uint ConvertFromHex(string sNumber)
        {
            return ConvertHexToInt(sNumber[0]) * 16 + ConvertHexToInt(sNumber[1]);
            
        }

        private uint ConvertHexToInt(char cSign)
        {
            if (char.IsNumber(cSign))
                return Convert.ToUInt32(cSign);
            switch (char.ToUpper(cSign))
            {
                case 'A':
                    return 10;
                case 'B':
                    return 11;
                case 'C':
                    return 12;
                case 'D':
                    return 13;
                case 'E':
                    return 14;
                default:
                    return 15;
            }
        }



        #region WPF Image Management

        private Point ConvertMousePosition(Point oldPos)
        {
            Point newPos = new Point();
            double size = Math.Min(RenderSize.Width, RenderSize.Height);
            newPos.X = (oldPos.X - _offsetX) * _imageSize / size;
            newPos.Y = (oldPos.Y - _offsetY) * _imageSize / size;
            return newPos;
        }


        public void LoadImages(string sImagePath)
        {
            _imageBoardClassic = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8.jpg"), out _rectBoard);
            _imageBoardBlackWhite = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8_blackandwhite.jpg"), out _rectBoard);
            _imageBoardMarble = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8_marble.jpg"), out _rectBoard);
            _imageBoardRotClassic = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8_rotation.jpg"), out _rectBoard);
            _imageBoardRotBlackWhite = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8_white_rotation.jpg"), out _rectBoard);
            _imageBoardRotMarble = PreloadImage(System.IO.Path.Combine(sImagePath, "board8x8_marble_rotation.jpg"), out _rectBoard);

            _imageWhiteMan = PreloadImage(System.IO.Path.Combine(sImagePath, "kamen_bily.png"), out _rectWhiteMan);
            _imageBlackMan = PreloadImage(System.IO.Path.Combine(sImagePath, "kamen_cerny.png"), out _rectBlackMan);
            _imageWhiteKing = PreloadImage(System.IO.Path.Combine(sImagePath, "dama_bila.png"), out _rectWhiteKing);
            _imageBlackKing = PreloadImage(System.IO.Path.Combine(sImagePath, "dama_cerna.png"), out _rectBlackKing);
            _imageBoard10 = PreloadImage(System.IO.Path.Combine(sImagePath, "sachovnice10.jpg"), out _rectBoard10);
        }


        protected BitmapSource PreloadImage(string strPath, out Rect rect)
        {
            rect = Rect.Empty;              
            BitmapImage image = new BitmapImage(new Uri(strPath));
            BitmapSource bs = image;

            rect = new Rect(new Point(0, 0), new Size(bs.PixelWidth, bs.PixelHeight));
            return bs;
        }

        protected void PreloadImages()
        {
        }


        protected BitmapSource GetImage(enumDrawnImage drawnImage, out Rect rect)
        {
            switch (drawnImage)
            {
                case enumDrawnImage.WhiteMan:
                    rect = _rectWhiteMan;
                    return _imageWhiteMan;
                case enumDrawnImage.BlackMan:
                    rect = _rectBlackMan;
                    return _imageBlackMan;
                case enumDrawnImage.WhiteKing:
                    rect = _rectWhiteKing;
                    return _imageWhiteKing;
                case enumDrawnImage.BlackKing:
                    rect = _rectBlackKing;
                    return _imageBlackKing;
                case enumDrawnImage.Board:
                    {
                        rect = _rectBoard;
                        switch (_theme)
                        {
                            case eBoard2DTheme.Classic:
                                return _imageBoardClassic;
                            case eBoard2DTheme.BlackAndWhite:
                                return _imageBoardBlackWhite;
                            case eBoard2DTheme.Marble:
                                return _imageBoardMarble;
                        }                        
                    }
                    return null;
                case enumDrawnImage.BoardRotated:
                    {
                        rect = _rectBoardRotated;
                        switch (_theme)
                        {
                            case eBoard2DTheme.Classic:
                                return _imageBoardRotClassic;
                            case eBoard2DTheme.BlackAndWhite:
                                return _imageBoardRotBlackWhite;
                            case eBoard2DTheme.Marble:
                                return _imageBoardRotMarble;
                        }                        
                    }
                    return null;
                case enumDrawnImage.Board10:
                    rect = _rectBoard10;
                    return _imageBoard10;
                default:
                    rect = Rect.Empty;
                    return null;
            }
        }
       
        #endregion
    }
}
